//
//  DDropingManager.swift
//  Drop
//
//  Created by hushaohua on 2017/12/21.
//  Copyright © 2017年 init. All rights reserved.
//

import UIKit
import CoreData
import UserNotifications

class DDroppingManager: NSObject {
    
    static let HDroppingDidNewNotification:String = "NewDroppingNotification";
    
    static let sharedInstance = DDroppingManager();
    class func sharedManager() -> DDroppingManager {
        return sharedInstance;
    }
    
    func load() -> Void {
        if (self.viewManager.tabWindow.isHidden){
            self.viewManager.setupDroppingWindow();
        }
    }
    
    override init() {
        super.init();
    }
    
    lazy var viewManager:DDroppingViewManager = {
        var manager:DDroppingViewManager = DDroppingViewManager();
        return manager;
    }();
    
    func gotoDropInto(_ drop:Drop){
        self.viewManager.gotoDropInto(drop);
    }
    
    func getDoingDrop() -> Void {
        let request:NSFetchRequest<Drop> = Drop.defaultFetchRequest();
        let sortDes:NSSortDescriptor = Drop.defaultSort();
        request.sortDescriptors = [sortDes];
        request.fetchLimit = 1;
        let drop = Drop.fetchInstancesFrom(request)?.first;
        if (drop != nil && drop!.end == nil){
            self.doingDrop = drop;
            self.viewManager.startAtDate(drop?.begin as Date?);
            if (self.doingDrop?.pushId == nil){
                self.addNotificationIfNotDisturb();
            }
        }
    }
    
    func getLastFinishedDrop() -> Drop? {
        let request:NSFetchRequest<Drop> = Drop.defaultFetchRequest();
        let sortDes:NSSortDescriptor = Drop.defaultSort();
        request.sortDescriptors = [sortDes];
        request.fetchLimit = 1;
        let predicate = NSPredicate(format: "tag != nil");
        request.predicate = predicate;
        let drop = Drop.fetchInstancesFrom(request)?.first;
        if (drop != nil && drop!.end != nil){
            return drop;
        }
        return nil;
    }
    
    var doingDrop:Drop?;
    func start() -> Void {
        if (self.doingDrop == nil){
            self.startDoingDropping();
        }
        self.viewManager.startAtDate(self.doingDrop?.begin as Date?);
        if (self.doingDrop?.pushId == nil){
            self.addNotificationIfNotDisturb();
        }
    }
    
    func finishDropsAt(_ currentDate:Date) -> Void{
//        let currentDate = Date();
        let beginDate:Date = self.doingDrop!.begin! as Date;
        var calendar = Calendar.current;
        calendar.firstWeekday = 2;
        if (calendar.isDate(currentDate, inSameDayAs: beginDate)){
            self.doingDrop?.end = currentDate as NSDate;
        }else{
            //begin day8
            //currentDate day11
            var nextDate = calendar.startOfDay(for: beginDate);//begin day8
            nextDate = Date(timeInterval: TimeInterval(3600 * 24), since: nextDate);//day9-begin
            let tag = self.doingDrop?.tag;
            while (currentDate.timeIntervalSince(nextDate) > 0){
                self.doingDrop?.end = Date(timeInterval: -1, since: nextDate) as NSDate;//day8-end
                self.doingDrop = Drop.newInstance();
                self.doingDrop!.tag = tag;
                self.doingDrop!.begin = nextDate as NSDate;//day9-begin
                nextDate = Date(timeInterval: TimeInterval(3600 * 24), since: nextDate);//day10-begin
            }
            if (self.doingDrop?.end == nil){
                self.doingDrop?.end = currentDate as NSDate;
            }
        }
    }
    
    func finish() -> Void {
        self.finishDropsAt(Date());
        HStoreManager.defaultManger().saveContext();
        self.doingDrop = nil;
        self.viewManager.stop();
    }
    
    func finishAt(_ date: Date) -> Void {
        self.finishDropsAt(date);
//        self.doingDrop?.end = date as NSDate;
        HStoreManager.defaultManger().saveContext();
        self.doingDrop = nil;
        
        self.startDoingDroppingAt(date);
        self.viewManager.startAtDate(self.doingDrop!.begin as Date?);
        self.addNotificationIfNotDisturb();
    }
    
    func revokeLatestDrop(_ drop:Drop){
        let interval = self.doingDrop!.begin!.timeIntervalSince(drop.end! as Date)
        if (interval < 1){
            self.removeNotification();
            self.doingDrop?.begin = drop.begin;
            drop.deleteFromContext();
            HStoreManager.defaultManger().saveContext();
            self.viewManager.startAtDate(self.doingDrop!.begin as Date?);
            NotificationCenter.default.post(name: Notification.Name(DDroppingManager.HDroppingDidNewNotification), object: nil);
            self.addNotificationIfNotDisturb();
        }
    }
    
    func finishAndStartNext() -> Void {
        self.removeNotification();
        self.finishDropsAt(Date());
        self.doingDrop = nil;
        
        self.startDoingDropping();
        self.viewManager.startAtDate(self.doingDrop!.begin as Date?);
        self.addNotificationIfNotDisturb();
    }
    
    func startDoingDroppingAt(_ date:Date) -> Void{
        self.doingDrop = Drop.newInstance();
        self.doingDrop!.begin = date as NSDate;
        HStoreManager.defaultManger().saveContext();
        NotificationCenter.default.post(name: Notification.Name(DDroppingManager.HDroppingDidNewNotification), object: nil);
    }
    
    func startDoingDropping() -> Void{
        self.startDoingDroppingAt(Date());
    }
    
    func addNotificationIfNotDisturb() -> Void{
        if (!DPreferences.defaultPreferences().doNotDisturb){
            UNUserNotificationCenter.current().removeAllPendingNotificationRequests();
            UNUserNotificationCenter.current().removeAllDeliveredNotifications();
            self.addDoingDropNotification();
        }
    }
    
    func refreshDoingNotifications() -> Void{
        UNUserNotificationCenter.current().removeAllPendingNotificationRequests();
        UNUserNotificationCenter.current().removeAllDeliveredNotifications();
        self.addDoingDropNotification();
    }
    
    func startDoingDropNotification() -> Void{
        if (self.doingDrop?.pushId != nil){
            self.addDoingDropNotification();
        }
    }
    
    func addDoingDropNotification() -> Void{
        
        let lastFinishedDrop = self.getLastFinishedDrop();
        let content = UNMutableNotificationContent();//myNotificationCategory
        content.categoryIdentifier = "myNotificationCategory";
        
        let dateFormatter:DateFormatter = DateFormatter();
        let beginDate:Date = self.doingDrop!.begin! as Date;
        dateFormatter.dateFormat = "HH:mm";
        content.title = "Drop";
        if (lastFinishedDrop != nil){
            content.body = "上次\(lastFinishedDrop!.tag!.name)结束于\(dateFormatter.string(from: beginDate))";
        }else{
            content.body = "开始于\(dateFormatter.string(from: beginDate))";
        }
        content.userInfo = ["date" : beginDate];
        let requestId:String = "\(Date().timeIntervalSince1970)";
        let notificationInterval:TimeInterval = TimeInterval(DPreferences.defaultPreferences().notificationInterval);
        let trigger = UNTimeIntervalNotificationTrigger(timeInterval: notificationInterval, repeats: true);
        let request = UNNotificationRequest(identifier: requestId, content: content, trigger: trigger);
        
        UNUserNotificationCenter.current().add(request) { (error) in
            if (error == nil){
                self.doingDrop?.pushId = requestId;
            }
        };
    }
    
    func removeNotification() -> Void{
        if (self.doingDrop?.pushId != nil){
            UNUserNotificationCenter.current().removeDeliveredNotifications(withIdentifiers: [(self.doingDrop?.pushId)!]);
            UNUserNotificationCenter.current().removePendingNotificationRequests(withIdentifiers: [(self.doingDrop?.pushId)!]);
        }
    }
    
    func changeNotificationInterval() {
        self.removeNotification();
        self.addDoingDropNotification();
    }
    
    func removeAllNotifications() {
        UNUserNotificationCenter.current().removeAllDeliveredNotifications();
        UNUserNotificationCenter.current().removeAllPendingNotificationRequests();
    }
}
